﻿//     Copyright (c) Microsoft Corporation.  All rights reserved.

using System;
using System.Linq;
using System.Net;
using System.Net.Http.Headers;
using System.Web.Http;
using System.Xml.Linq;
using Gateway.UpdateService.Controllers;
using Gateway.UpdateService.Models;
using Microsoft.Gateway.Utils;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace UpdateService.Tests.Controllers
{
    [TestClass]
    public class GatewayControllerTest
    {
        string _containerUri;
        GatewayController _controller;
        ManagementConsoleController _consoleController;

        static readonly Version FirstManifestVersion    = Version.Parse("0.1");
        static readonly Version SecondManifestVersion   = Version.Parse("0.1.3");
        static readonly Version DisabledManifestVersion = Version.Parse("0.7");
        static readonly Version ConsoleManifestVersion  = Version.Parse("1.0");

        public GatewayControllerTest()
        {
            _containerUri = AzureUtils.GetConfigSetting("PackagesContainer", "");
            _controller = new GatewayController(_containerUri, AzureUtils.GetConfigSetting("GatewayPackagesDirectory", ""));
            _consoleController = new ManagementConsoleController(_containerUri, AzureUtils.GetConfigSetting("ConsolePackagesDirectory", ""));
        }

        [TestMethod]
        public void UpdateGetGatewayManifests()
        {
            // Act
            var result = _controller.Get().Result;

            // Assert
            Assert.IsNotNull(result);
            Assert.AreEqual(2, result.Count());
            var firstManifest = result.FirstOrDefault();
            Assert.AreEqual(FirstManifestVersion, firstManifest.Version);
            Assert.AreEqual("Initial", firstManifest.Description);
            Assert.AreEqual(UpdateSeverity.Important, firstManifest.Severity);
            var secondManifest = result.FirstOrDefault(manifest => manifest.Version == SecondManifestVersion);
            Assert.IsNotNull(secondManifest);
            Assert.AreEqual("Fixed bugs", secondManifest.Description);
            Assert.AreEqual(UpdateSeverity.Important, secondManifest.Severity);
            Assert.AreEqual(2, secondManifest.AvailablePackages.Count);
        }

        [TestMethod]
        public void UpdateGetManagementConsoleManifests()
        {
            // Act
            var result = _consoleController.Get().Result;

            // Assert
            Assert.IsNotNull(result);
            Assert.AreEqual(1, result.Count());
            var firstManifest = result.FirstOrDefault();
            Assert.AreEqual(ConsoleManifestVersion, firstManifest.Version);
        }

        [TestMethod]
        public void UpdateGetManifestById()
        {
            // Act
            var result = _controller.Get(SecondManifestVersion.GatewayFormat()).Result;

            // Assert
            Assert.IsNotNull(result);
            Assert.AreEqual(SecondManifestVersion, result.Version);
        }

        [TestMethod]
        public void UpdateGetDisabledManifest()
        {
            // Act
            var result = _controller.Get(DisabledManifestVersion.GatewayFormat()).Result;

            // Assert
            Assert.IsNotNull(result);
            Assert.AreEqual(DisabledManifestVersion, result.Version);
        }

        [TestMethod]
        public void UpdateGetMostRecentVersion()
        {
            try
            {
                var tmp = _controller.GetManifestByMoreRecent(SecondManifestVersion.GatewayFormat()).Result;
                Assert.Fail("Expected NotFound (404) exception to be thrown.");
            }
            catch (AggregateException ex)
            {
                ex.Handle(innerEx =>
                    {
                        if (innerEx is HttpResponseException)
                        {
                            if (((HttpResponseException)innerEx).Response.StatusCode == HttpStatusCode.NotFound)
                            {
                                return true;
                            }
                        }
                        Assert.Fail("Expected NotFound (404) exception");
                        return false;
                    });
            }
            var result = _controller.GetManifestByMoreRecent(FirstManifestVersion.GatewayFormat()).Result;
            Assert.IsNotNull(result);
            Assert.AreEqual(SecondManifestVersion, result.Version);
        }

        [TestMethod]
        public void UpdateGetLatestVersion()
        {
            var result = _controller.Get("latest").Result;
            Assert.IsNotNull(result);
            Assert.AreEqual(SecondManifestVersion, result.Version);
        }

        [TestMethod]
        public void UpdateGetHttpConfigurationContents()
        {
            var result = _controller.GetFileContents(SecondManifestVersion.GatewayFormat(), "http", "ServiceConfiguration.Publish.cscfg", false, null).Result;
            Assert.IsNotNull(result);
            Assert.IsTrue(result.IsSuccessStatusCode);
            Assert.AreEqual(1071, result.Content.Headers.ContentLength.Value);
            string contents = result.Content.ReadAsStringAsync().Result;
            
            var doc = XDocument.Parse(contents);
            XNamespace ns = "http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration";
            var instancesElement = doc.Root.DescendantNodes().FirstOrDefault(node => ((XElement)node).Name == ns + "Instances") as XElement;
            Assert.IsNotNull(instancesElement);
            var instanceCount = instancesElement.Attribute("count");
            Assert.AreEqual(2, int.Parse(instanceCount.Value));
        }

        [TestMethod]
        public void UpdateGetHttpsConfigurationContents()
        {
            var result = _controller.GetFileContents(SecondManifestVersion.GatewayFormat(), "https", "ServiceConfiguration.Publish.cscfg", false, null).Result;
            Assert.IsNotNull(result);
            Assert.IsTrue(result.IsSuccessStatusCode);
            Assert.AreEqual(1244, result.Content.Headers.ContentLength.Value);
            string contents = result.Content.ReadAsStringAsync().Result;

            var doc = XDocument.Parse(contents);
            XNamespace ns = "http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration";
            var certElement = doc.Root.DescendantNodes().FirstOrDefault(node => ((XElement)node).Name == ns + "Certificate") as XElement;
            Assert.IsNotNull(certElement);
            Assert.AreEqual("0000000000000000000000000000000000000000", certElement.Attribute("thumbprint").Value);
        }

        [TestMethod]
        public void HeadHttpsConfigurationContents()
        {
            var result = _controller.GetFileContents(SecondManifestVersion.GatewayFormat(), "https", "ServiceConfiguration.Publish.cscfg", true, null).Result;
            Assert.IsNotNull(result);
            Assert.IsTrue(result.IsSuccessStatusCode);
            Assert.AreEqual(1244, result.Content.Headers.ContentLength.Value);
            Assert.AreEqual(result.Headers.AcceptRanges.Single(), "bytes");
        }

        [TestMethod]
        public void GetHttpsConfigurationContentsRange()
        {
            var result = _controller.GetFileContents(SecondManifestVersion.GatewayFormat(), "https", "ServiceConfiguration.Publish.cscfg", false, new RangeHeaderValue(100, 140)).Result;
            Assert.IsNotNull(result);
            Assert.AreEqual(HttpStatusCode.PartialContent, result.StatusCode);
            Assert.AreEqual(41, result.Content.Headers.ContentLength.Value);
            Assert.AreEqual(100, result.Content.Headers.ContentRange.From);
            Assert.AreEqual(140, result.Content.Headers.ContentRange.To);
            Assert.AreEqual(1244, result.Content.Headers.ContentRange.Length);
            Assert.AreEqual("bytes", result.Content.Headers.ContentRange.Unit);
            string contents = result.Content.ReadAsStringAsync().Result;
            Assert.AreEqual("*****************************************", contents);
        }
    }
}
